import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Map;
import java.util.Random;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import momo.app.multicast.Msg;
import momo.app.multicast.MsgRcvListener;
import momo.app.multicast.MulticastComm;
import momo.app.util.FileOutput;

public class TestApp implements MsgRcvListener
{
	final private String sentData;
	final private boolean isServer;
	final private String id;
	final private int statusPort, commPort;
	final private String clientIP;
	final private int clientPort;
	
	private boolean hasConnect;
	private MulticastComm comm;
	
	private Log log = LogFactory.getLog(TestApp.class);
	
	private boolean sendAvailable;
	
	public TestApp(boolean isServer, String id, int statusPort, String clientIP, int clientPort)
	{
		this.isServer = isServer;
		this.id = id;
		this.statusPort = statusPort;
		this.commPort = statusPort + 1;
		this.clientIP = clientIP;
		this.clientPort = clientPort;
		
		this.sendAvailable = true;
		this.sentData = getTextContents("./trial_2.txt");
		this.comm = new MulticastComm(this.id, this.commPort, this.statusPort);
		comm.addMsgRcvListener(this);
		
		hasConnect = false;
	}
	
	public void runSim()
	{
		this.connect();
		this.send();
		
		if ( !this.isServer )
		{
			Thread t = new Thread()
			{
				public void run()
				{
					Random rand = new Random();
					while(true)
					{
						try {
							sleep(2000);
							if ( rand.nextDouble() > 0.15 )
							{
								if ( !hasConnect )
									connect();
							}else
							{
								if ( hasConnect )
									disconnect();
							}
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
				}
			};
			t.start();
		}
	}
	
	private void connect()
	{
		try {
			System.out.println("Connect state");
			comm.connect(this.clientIP, this.clientPort);
			hasConnect = true;
		} catch (IOException e) {
			hasConnect = false;
			e.printStackTrace();
		}
	}
	
	private void disconnect()
	{
		System.out.println("Disconnect state");
		comm.leave();
		hasConnect = false;
	}
	
	private void send()
	{
		Thread t = new Thread()
		{
			public void run()
			{
				while(sendAvailable)
				{
					try
					{
						sleep(1 * 1000);
						comm.synchronizedSend(sentData);
					}catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
		};
		t.start();
	}
	
	private String getTextContents(String filename)
	{
		File f = new File(filename);
		StringBuffer buffer = new StringBuffer();
		try {
			BufferedReader in = new BufferedReader(new FileReader(f));
			String line = "";
			String lineSep = System.getProperty("line.separator");
			while( (line=in.readLine()) != null )
			{
				buffer.append(line);
				buffer.append(lineSep);
			}
		}catch (IOException e) {
			e.printStackTrace();
			buffer.append("Msg not found in file. Sending this instead");
		}
		return buffer.toString();
	}
	
	public void msgLost(Map<String, Set<Integer>> lostMsg)
	{
	}

	public void msgReceived(Msg msg)
	{
		if ( !msg.getSource().equals(this.id) )
		{
			String rcvedData = msg.getContents();
			boolean isMatch = rcvedData.equals(sentData)? true:false;
			String contents = isMatch ? "Data Matched\n" : "~~~~~~~~ Data Diff ~~~~~~~~\nSent:\n"+sentData+"\n\nRcv:\n"+rcvedData; 
			FileOutput.getInstance().logToFile("Match.txt", contents);
			if ( !isMatch )
				log.warn("@@@@@@@@@@@@@@@@@@@ Fail to match @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
//			else
//				log.warn("MATCH");
		}
	}
	
	public static void main(String args[])
	{
		boolean isServer = true;
		String id = "A";
		int statusPort = 1111;
		String clientIP = "";
		int clientPort = 2222;
		
		isServer = args[0].equals("s")?true:false;
//		id = args[1];
//		statusPort = Integer.parseInt(args[2]);
//		clientIP = isServer?"":args[3];
//		clientPort = Integer.parseInt(args[4]);
		
		if ( !isServer )
		{
			id = "B";
			statusPort = 2222;
			clientIP = "155.69.144.148";
			clientPort = 1111;
		}
		
		TestApp app = new TestApp(isServer, id, statusPort, clientIP, clientPort);
		app.runSim();
		
	}
}//end of class TestApp
